package away3d.animators.skeleton ;

/**
 * Author: David Lenaerts
 */


import away3d.core.math.Quaternion ;
import flash.geom.Vector3D ;



class SkeletonAdditiveNode extends SkeletonTreeNode
{
    
    
    public var baseInput            : SkeletonTreeNode ;
    public var differenceInput      : SkeletonTreeNode ;
    private var _blendWeight        : Float ;
    private static var _tempQuat    : Quaternion ;
    
    
    
    public function new()
    {
        
        super() ;
        _blendWeight    = 0 ;
        _tempQuat       = new Quaternion() ;
        
    }
    
    
    override public var duration( get_duration, set_duration ): Float ;
    
    
    override private function get_duration() : Float
    {
        
        return baseInput.duration ;
        
    }
    
    
    public var blendWeight( get_blendWeight, set_blendWeight ) : Float ;
    
    
    public function get blendWeight() : Float
    {
        
        return _blendWeight ;
        
    }
    
    
    public function set_blendWeight( value : Float ) : Float
    {
        _blendWeight    = value ;
        _duration       = baseInput.duration ;
        return value ;
        
    }
    
    
    public var time( null, set_time ): Float ;
    
    
    override private function set_time( value: Float ) : Float   
    {
        
        baseInput.time          = value ;
        differenceInput.time    = value ;
        //TODO: super.time ... not sure that will work!
        super.time              = value ;
        
        return value ;
        
    }
    
    
    public function direction( null, get_direction ) : Float ;
    
    
    override public function set direction( value: Float ) : Float
    {
        
        baseInput.direction         = value;
        differenceInput.direction   = value;
        super.direction             = value;
        
    }
    
    
    // todo: return whether or not update was performed
    override public function updatePose( skeleton : Skeleton )
    {
        
        // todo: should only update if blendWeight dirty, or if either child returns false
        baseInput.updatePose( skeleton ) ;
        differenceInput.updatePose( skeleton ) ;
        
        var endPose     : JointPose ;
        var endPoses                    = skeletonPose.jointPoses ;
        var basePoses                   = baseInput.skeletonPose.jointPoses ;
        var diffPoses                   = differenceInput.skeletonPose.jointPoses ;
        var base        : JointPose ; 
        var diff        : JointPose ;
        var basePos     : Vector3D ;
        var diffPos     : Vector3D ;
        var tr          : Vector3D ;
        var numJoints                   = skeleton.numJoints ;
        
        // :s
        if( endPoses.length != numJoints ) endPoses.length = numJoints ;
        
        for( i in 0...numJoints )
        {
            
            endPose     = endPoses[ i ] ;
            
            if( endPose == null ) endPos = new JointPose() ;
            
            base        = basePoses[ i ] ;
            diff        = diffPoses[ i ] ;
            basePos     = base.translation ;
            diffPos     = diff.translation ;
            
            _tempQuat.multiply( diff.orientation, base.orientation ) ;
            endPose.orientation.lerp( base.orientation, _tempQuat, _blendWeight ) ;
            
            tr          = endPose.translation ;
            tr.x        = basePos.x + _blendWeight*diffPos.x ;
            tr.y        = basePos.y + _blendWeight*diffPos.y ;
            tr.z        = basePos.z + _blendWeight*diffPos.z ;
            
        }
        
    }
    
    
    override public function updatePositionData()
    {
        
        var deltA       = baseInput.rootDelta   ;
        var deltB       = differenceInput.rootDelta ;
        
        rootDelta.x     = deltA.x + _blendWeight*deltB.x ;
        rootDelta.y     = deltA.y + _blendWeight*deltB.y ;
        rootDelta.z     = deltA.z + _blendWeight*deltB.z ;
        
    }
    
    
}
